package com.gopay.bis.icbc.bcdl.impl;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import com.gopay.common.cipher.utils.LoggerMaskUtils;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.infosec.util.Base64;

import com.gopay.bis.common.trace.PaymentLog;
import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.common.util.TransUtil;
import com.gopay.bis.icbc.bcdl.operation.HttpTransport;
import com.gopay.bis.icbc.bcdl.operation.HttpTransportForSign;
import com.gopay.bis.icbc.bcdl.operation.QueryAcctDetailformer;
import com.gopay.bis.icbc.bcdl.operation.QueryBalformer;
import com.gopay.bis.icbc.bcdl.operation.Queryformer;
import com.gopay.bis.icbc.bcdl.operation.Transformer;
import com.gopay.common.constants.bank.BankLogConstants;
import com.gopay.common.constants.bank.BisBankInterfaceChannel;
import com.gopay.common.constants.bank.IcbcConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.BisBankReturnVo;
import com.gopay.common.domain.bank.icbc.bcdl.pay.IcbcMessageData;
import com.gopay.common.domain.bank.icbc.bcdl.pay.IcbcPacketMessage;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;
import com.gopay.remote.bank.businesses.BcdlService;

public class IcbcBcdlServiceImpl implements BcdlService {
	private final static Logger logger = LoggerFactory.getLogger("BANK_LOG");
	Transformer transformer;
	HttpTransportForSign signTransport;
//	HttpTransport transport;
	Queryformer queryformer;
	HttpTransport queryTransport;
	QueryBalformer queryBalformer;
	QueryAcctDetailformer qryAcctDetailformer;
	private String STR ="/servlet/ICBCCMPAPIReqServlet";
	private String channles;
	private String label;
	private List<String> urls;
//  @Resource(name = "signUrls")
    private Map<String,String> signUrls;
//  @Resource(name = "ids")
    private Map<String,String> ids;
    //kafka开关
    private String kafkaSwitch;
    
    
	
	@Override
	public Object query(Object obj) throws GopayException {
		String url ="";
		String id = "";
		String another="";
		for (String str : urls) {
			if(channles.startsWith(str)){
				id = ids.get(str);
				url = str+STR;
			}else{
				another = str;
			}
		}
		try{
			IcbcMessageData sendMsgData=(IcbcMessageData) obj;
			
			BankLogUtils.printBcdlQuerySendLog(sendMsgData);
			// Format original data to wire up message body
			Object formatRes = queryformer.format(obj,id);
			// Parameter preparation
			Map issueNCParaMap = queryformer.getIssueNCParaMap(obj, formatRes);
			// Issue NetSafeClient Encryption Server
			queryTransport.setUrl(url);
			Object issueRes = queryTransport.submit(issueNCParaMap);
			// Resolve response body
			String msgBody = resolveResMsgBody(issueRes);
			// Parse returned message
			Object obj3 = queryformer.parse(msgBody);
			IcbcMessageData returnMsgData=(IcbcMessageData) obj3;
			logger.error("IcbcMessageData:", ToStringBuilder.reflectionToString(returnMsgData));
			BankLogUtils.printBcdlQueryReturnLog(returnMsgData);
			saveQueryKafkaInfo(sendMsgData, returnMsgData, new String(msgBody.getBytes("UTF-8"), "GBK"));
			return obj3;
		}catch(GopayException e){
			if(ProcCodeConstants.PROC_CODE_100E6047.equals(e.getErrCode())){
				throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6047,"连接前置机"+url);
			}else{
				throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
			}
		}catch(Exception e){
		    logger.error(" icbc bcdl  query error message: ", e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6049);
		}
	}
	
	@Override
	public Object eft(Object obj) throws GopayException {
		String url ="";
		String signUrl="";
		String id = "";
		String another="";
		for (String str : urls) {
			if(channles.startsWith(str)){
				id = ids.get(str);
				signUrl=signUrls.get(str);
				url = str+STR;
			}else{
				another = str;
			}
		}
		try{
		    logger.info(" icbc bcdl  eft id: " + id + " icbc bcdl  eft signUrl: " + signUrl
		            + " icbc bcdl  eft url: " + url);
			IcbcMessageData sendMsgData=(IcbcMessageData) obj;
			logger.info(" lable_" + label + ", gopayOrderId: " + sendMsgData.getfSeqno() + ", eft url: " + url);
			BankLogUtils.printBcdlEftSignSendLog(sendMsgData);
			// Format original data to wire up message body
			Object formatRes = transformer.doFormat((IcbcMessageData)obj,id);
			
			// Parameter preparation
			Map issueNCParaMap = transformer.getIssueNCParaMap(obj, formatRes,signUrl);
			// Issue NetSafeClient Encryption Server
			HttpTransport transport = new HttpTransport();
			transport.setUrl(url);
			Object issueRes = transport.submit(issueNCParaMap);
			// Resolve response body
			String msgBody = resolveResMsgBody(issueRes);
			// Parse returned message
			Object obj3 = transformer.parse(msgBody);
			logger.info(" icbc bcdl  eft return message: "
					+ LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(obj3)));
			IcbcMessageData returnMsgData=(IcbcMessageData) obj3;
			BankLogUtils.printBcdlEftReturnLog(returnMsgData);
			//工行单笔付款保存到kafka中  add by wjq 20171221
			saveEftKafkaInfo(sendMsgData, returnMsgData, new String(msgBody.getBytes("UTF-8"), "GBK"));
			return obj3;
		}catch(GopayException e){
			if(ProcCodeConstants.PROC_CODE_100E6047.equals(e.getErrCode())){
				//channles=another;
				throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6047,"前置机地址"+url);
			}else if(ProcCodeConstants.PROC_CODE_100E6082.equals(e.getErrCode())){
                throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6082,"签名失败, 前置机地址"+signUrl);
            }else{
				throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
			}
		}catch(Exception e){
            logger.error(" icbc bcdl  eft error message: ", e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
		}
	}
	
	@Override
	public Object queryBalance(Object obj) throws GopayException {
		String url ="";
		String id = "";
		String another="";
		for (String str : urls) {
		    logger.error("str" + str + "queryBalance");
			if(channles.startsWith(str)){
				id = ids.get(str);
				url = str+STR;
				logger.error("id" + id + "queryBalance");
				logger.error("url" + url + "queryBalance");
			}else{
				another = str;
			}
		}
		
		try{
			IcbcMessageData sendMsgData=(IcbcMessageData) obj;
			
			BankLogUtils.printBcdlQuerySendLog(sendMsgData);
			// Format original data to wire up message body
			Object formatRes = queryBalformer.format(obj,id);
			// Parameter preparation
			Map issueNCParaMap = queryBalformer.getIssueNCParaMap(obj, formatRes);
			// Issue NetSafeClient Encryption Server
			queryTransport.setUrl(url);
			Object issueRes = queryTransport.submit(issueNCParaMap);
			// Resolve response body
			String msgBody = resolveResMsgBody(issueRes);
			// Parse returned message
			Object obj3 = queryBalformer.parse(msgBody);
			IcbcMessageData returnMsgData=(IcbcMessageData) obj3;
			BankLogUtils.printBcdlQueryReturnLog(returnMsgData);
			return obj3;
		}catch(GopayException e){
			if(ProcCodeConstants.PROC_CODE_100E6047.equals(e.getErrCode())){
				throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6047,"连接前置机"+url);
			}else{
				throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
			}
		}catch(Exception e){
		    logger.error(" icbc bcdl  queryBalance error message: ", e);
			throw new GopayException(ProcCodeConstants.PROC_CODE_100E6049);
		}
	}

	@Override
    public Object packetEft(Object object) throws GopayException {
	    String url ="";
        String signUrl="";
        String id = "";
        String another="";
        for (String str : urls) {
            if(channles.startsWith(str)){
                id = ids.get(str);
                signUrl=signUrls.get(str);
                url = str+STR;
            }else{
                another = str;
            }
        }
        try{
            logger.info(" icbc bcdl  packetEft id: " + id + " icbc bcdl  packetEft signUrl: " + signUrl
                    + " icbc bcdl  packetEft url: " + url);
            IcbcPacketMessage sendMsgData = (IcbcPacketMessage) object;
            logger.info(" lable_" + label + ", packetNo: " + sendMsgData.getPacketNo() + ", eft url: " + url);
//            BankLogUtils.printBcdlEftSignSendLog(sendMsgData);
            // Format original data to wire up message body
            Object formatRes = transformer.doPacketFormat(sendMsgData,id);
            
            // Parameter preparation
            Map issueNCParaMap = transformer.getPacketIssueNCParaMap(object, formatRes, signUrl);
            // Issue NetSafeClient Encryption Server
            HttpTransport transport = new HttpTransport();
            transport.setUrl(url);
            Object issueRes = transport.submit(issueNCParaMap);
            // Resolve response body
            String msgBody = resolveResMsgBody(issueRes);
            // Parse returned message
            Object obj3 = transformer.packetDataParse(msgBody);
            logger.info(" icbc bcdl  packetEft return message: " + ToStringBuilder.reflectionToString(obj3));
            IcbcMessageData returnMsgData = (IcbcMessageData) obj3;
            returnMsgData.setfSeqno(sendMsgData.getPacketNo());
            BankLogUtils.printBcdlEftReturnLog(returnMsgData);
            return obj3;
        }catch(GopayException e){
            if(ProcCodeConstants.PROC_CODE_100E6047.equals(e.getErrCode())){
                //channles=another;
                throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6047,"批量接口前置机地址"+url);
            }else if(ProcCodeConstants.PROC_CODE_100E6082.equals(e.getErrCode())){
                throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6082,"批量接口签名失败, 前置机地址"+signUrl);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
            }
        }catch(Exception e){
            logger.error(" icbc bcdl  packetEft error message: ", e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
        }
    }

    @Override
    public Object queryPacket(Object object) throws GopayException {
        String url ="";
        String id = "";
        String another="";
        for (String str : urls) {
            if(channles.startsWith(str)){
                id = ids.get(str);
                url = str+STR;
            }else{
                another = str;
            }
        }
        try{
            IcbcPacketMessage sendMsgData = (IcbcPacketMessage) object;
            
            BankLogUtils.printBcdlQuerySendLog(sendMsgData);
            // Format original data to wire up message body
            Object formatRes = queryformer.packetFormat(sendMsgData, id);
            // Parameter preparation
            Map issueNCParaMap = queryformer.getPacketIssueNCParaMap(object, formatRes);
            // Issue NetSafeClient Encryption Server
            queryTransport.setUrl(url);
            Object issueRes = queryTransport.submit(issueNCParaMap);
            // Resolve response body
            String msgBody = resolveResMsgBody(issueRes);
            // Parse returned message
            Object obj3 = queryformer.packetDataParse(msgBody);
            IcbcPacketMessage returnMsgData = (IcbcPacketMessage) obj3;
            BankLogUtils.printBcdlQueryReturnLog(returnMsgData);
            return obj3;
        }catch(GopayException e){
            if(ProcCodeConstants.PROC_CODE_100E6047.equals(e.getErrCode())){
                throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6047,"批量接口连接前置机"+url);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
            }
        }catch(Exception e){
            logger.error(" icbc bcdl  queryPacket error message: ", e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6049);
        }
    }

    @Override
    public Object queryAcctDetail(Object object) throws GopayException {
        String url ="";
        String id = "";
        String another="";
        for (String str : urls) {
            logger.error("str" + str + "queryAcctDetail");
            if(channles.startsWith(str)){
                id = ids.get(str);
                url = str+STR;
                logger.error("id" + id + "queryAcctDetail");
                logger.error("url" + url + "queryAcctDetail");
            }else{
                another = str;
            }
        }
        
        try{
            IcbcMessageData sendMsgData=(IcbcMessageData) object;
            
            BankLogUtils.printBcdlQuerySendLog(sendMsgData);
            // Format original data to wire up message body
            Object formatRes = qryAcctDetailformer.format(sendMsgData,id);
            // Parameter preparation
            Map issueNCParaMap = qryAcctDetailformer.getIssueNCParaMap(sendMsgData, formatRes);
            // Issue NetSafeClient Encryption Server
            queryTransport.setUrl(url);
            Object issueRes = queryTransport.submit(issueNCParaMap);
            // Resolve response body
            String msgBody = resolveResMsgBody(issueRes);
            msgBody = new String(msgBody.getBytes("UTF-8"), "GBK");
            String plainMsg = "";
            plainMsg = new String(Base64.decode(msgBody), "GBK");
            qryAcctDetailformer.saveFiles(sendMsgData, plainMsg);
                
            sendMsgData.setNextTag(""); // 设置返回下标
            String nextTag = TransUtil.getMsgField(IcbcConstants.NEXT_TAG_BEGIN_TAG_NEW,
                    IcbcConstants.NEXT_TAG_END_TAG_NEW, plainMsg);
            if (StringUtils.isNotEmpty(nextTag)) {
                // 银行返回有下页标识继续查询
                sendMsgData.setNextTag(nextTag);
            } else {
                // 银行返回无下页标识查询结束
                qryAcctDetailformer.saveFiles(sendMsgData, "########");
            }
            
            // Parse returned message
//            Object obj3 = qryAcctDetailformer.parse(msgBody);
//            IcbcMessageData returnMsgData=(IcbcMessageData) obj3;
//            BankLogUtils.printBcdlQueryReturnLog(returnMsgData);
            sendMsgData.setRetCode(IcbcConstants.QUERYBAL_STATUS_SUBMIT_SUCC);
            return sendMsgData;
        }catch(GopayException e){
            if(ProcCodeConstants.PROC_CODE_100E6047.equals(e.getErrCode())){
                throw  new GopayException(ProcCodeConstants.PROC_CODE_100E6047,"连接前置机"+url);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6049);
            }
        }catch(Exception e){
            logger.error(" icbc bcdl queryAcctDetail error message: ", e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6049);
        }
    }
	
	/**
	 * 鍙栨姤鏂囦綋锛屽鏋滆繑鍥為敊璇垯鎶涘嚭寮傚父锛岃鏄庤姹傚弬鏁版牸寮忎笉瀵�
	 * 
	 * @param issueRes
	 *            鎶ユ枃.
	 * @return 宸ヨ搴旂瓟鎶ユ枃浣�
	 * @throws GopayException
	 *             鎶ユ枃鏍煎紡閿欒.
	 */
	public String resolveResMsgBody(Object issueRes) throws GopayException {
		byte[] resByte = (byte[]) issueRes;
		String resStr = new String(resByte);
		int index = resStr.indexOf(IcbcConstants.NORMAL_RES_FIELD);
		if (index != -1) {
			String msgBody = resStr.substring(IcbcConstants.NORMAL_RES_FIELD
					.length());
			return msgBody;
		} else {
			throw new GopayException(resStr);
		}
	}
	
	/**
	 * 将单笔付款返回的报文记录到kafka中
	 * @param baseMsg
	 * @param resMessage
	 * @param plainText
	 * @throws IOException
	 */
	private void saveEftKafkaInfo(IcbcMessageData baseMsg, IcbcMessageData resMessage, String plainText) {
		try {
			BisBankReturnVo vo = new BisBankReturnVo();
			//国付宝订单号
			vo.setGopayOrderId(baseMsg.getfSeqno());
			//银行返回订单号
			vo.setBankOrderId(resMessage.getfSeqno());
			//银行渠道
			vo.setBankChannel(BisBankInterfaceChannel._00.value);
			//银行编码
			vo.setBankCode(BankLogConstants.BANK_LOG_BCDL_EFT_ICBC);
			//银行返回错误的xml文件信息
			vo.setBankReturnXml(new String(Base64.decode(plainText),"GBK"));
			//银行返回错误码
			vo.setRsCode(resMessage.getResult()); //指令状态
			//银行返回的错误信息
			vo.setRsMsg(resMessage.getIRetMsg().trim()); //交易返回描述
			//银行报文订单返回时间
			vo.setBankReturnDate(DateUtils.getCurrDate("yyyy-MM-dd HH:mm:ss"));
			//报文返回记录日志时间  时间格式：yyyy-MM-dd HH:mm:ss
			vo.setCreateTsErr(DateUtils.getCurrDate("yyyy-MM-dd HH:mm:ss"));
			//保存到kafka中
			PaymentLog.info(vo,kafkaSwitch);
		} catch (Exception e) {
			logger.error("工行单笔付款返回的报文记录到kafka异常："+e);
		}
		
	}
	
	
	/**
	 * 将单笔查询返回的报文记录到kafka中
	 * @param baseMsg
	 * @param resMessage
	 * @param plainText
	 * @throws IOException
	 */
	private void saveQueryKafkaInfo(IcbcMessageData baseMsg, IcbcMessageData resMessage, String plainText){
		try {
			BisBankReturnVo vo = new BisBankReturnVo();
			//国付宝订单号
			vo.setGopayOrderId(baseMsg.getfSeqno());
			//银行返回订单号
			vo.setBankOrderId(resMessage.getfSeqno());
			//银行渠道
			vo.setBankChannel(BisBankInterfaceChannel._00.value);
			//银行编码
			vo.setBankCode(BankLogConstants.BANK_LOG_BCDL_QUERY_ICBC);
			//银行返回错误的xml文件信息
			vo.setBankReturnXml(new String(Base64.decode(plainText),"GBK"));
			if(resMessage.getResult()!=null){
				//银行返回错误码
				vo.setRsCode(resMessage.getResult()); //指令状态
			}else{
				vo.setRsCode(resMessage.getRetCode());
			}
			//银行返回的错误信息
			vo.setRsMsg(resMessage.getInstrRetMsg()); //交易返回描述
			//银行报文订单返回时间
			vo.setBankReturnDate(DateUtils.getCurrDate("yyyy-MM-dd HH:mm:ss"));
			//报文返回记录日志时间  时间格式：yyyy-MM-dd HH:mm:ss
			vo.setCreateTsErr(DateUtils.getCurrDate("yyyy-MM-dd HH:mm:ss"));
			//保存到kafka中
			PaymentLog.info(vo,kafkaSwitch);
		} catch (Exception e) {
			logger.error("工行单笔查询返回的报文记录到kafka异常："+e);
		}
		
	}
	
	

	public HttpTransportForSign getSignTransport() {
		return signTransport;
	}

	public void setSignTransport(HttpTransportForSign signTransport) {
		this.signTransport = signTransport;
	}


	public Transformer getTransformer() {
		return transformer;
	}


	public void setTransformer(Transformer transformer) {
		this.transformer = transformer;
	}


//	public HttpTransport getTransport() {
//		return transport;
//	}
//
//
//	public void setTransport(HttpTransport transport) {
//		this.transport = transport;
//	}


	public Queryformer getQueryformer() {
		return queryformer;
	}


	public void setQueryformer(Queryformer queryformer) {
		this.queryformer = queryformer;
	}
	
	
	public QueryBalformer getQueryBalformer() {
		return queryBalformer;
	}


	public void setQueryBalformer(QueryBalformer queryBalformer) {
		this.queryBalformer = queryBalformer;
	}


	public HttpTransport getQueryTransport() {
		return queryTransport;
	}

	public void setQueryTransport(HttpTransport queryTransport) {
		this.queryTransport = queryTransport;
	}



	public String getChannles() {
		return channles;
	}


	public void setChannles(String channles) {
		this.channles = channles;
	}


	public String getLabel() {
		return label;
	}


	public void setLabel(String label) {
		this.label = label;
	}


	public List<String> getUrls() {
		return urls;
	}


	public void setUrls(List<String> urls) {
		this.urls = urls;
	}


	public Map<String, String> getSignUrls() {
		return signUrls;
	}


	public void setSignUrls(Map<String, String> signUrls) {
		this.signUrls = signUrls;
	}


	public Map<String, String> getIds() {
		return ids;
	}


	public void setIds(Map<String, String> ids) {
		this.ids = ids;
	}

    public QueryAcctDetailformer getQryAcctDetailformer() {
        return qryAcctDetailformer;
    }

    public void setQryAcctDetailformer(QueryAcctDetailformer qryAcctDetailformer) {
        this.qryAcctDetailformer = qryAcctDetailformer;
    }

	public String getKafkaSwitch() {
		return kafkaSwitch;
	}

	public void setKafkaSwitch(String kafkaSwitch) {
		this.kafkaSwitch = kafkaSwitch;
	}
	
	
}	
